package com.zhengqing.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.zhengqing.common.base.exception.MyException;
import com.zhengqing.common.file.config.MinIoProperties;
import com.zhengqing.common.redis.constant.RedisConstant;
import com.zhengqing.common.redis.util.RedisUtil;
import com.zhengqing.system.config.KafkaSendResultHandler;
import com.zhengqing.system.entity.ManualBrand;
import com.zhengqing.system.entity.ManualCatalogOm;
import com.zhengqing.system.entity.ManualModelOm;
import com.zhengqing.system.enums.ManualBrandEnums;
import com.zhengqing.system.mapper.ManualBrandMapper;
import com.zhengqing.system.mapper.ManualCatalogOmMapper;
import com.zhengqing.system.mapper.ManualModelOmMapper;
import com.zhengqing.system.model.dto.ManualCatalogToMailDto;
import com.zhengqing.system.model.dto.ManualModelSearchDto;
import com.zhengqing.system.model.vo.ManualModelSearchDetailVo;
import com.zhengqing.system.model.vo.ManualModelSearchVo;
import com.zhengqing.system.service.IManualModelOmService;
import com.zhengqing.system.util.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.concurrent.ListenableFuture;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class ManualModelOmServiceImpl extends ServiceImpl<ManualModelOmMapper, ManualModelOm> implements IManualModelOmService {
    
    private final ManualCatalogOmMapper catalogOmMapper;
    private final KafkaTemplate kafkaTemplate;
    private final ManualBrandMapper manualBrandMapper;
    private final MinIoProperties minIoProperties;

    private static SnowFlakeUtil idGenerator = new SnowFlakeUtil(0, 0);

    @Override
    public IPage<ManualModelSearchVo> searchModel(ManualModelSearchDto param) {
        IPage<ManualModelSearchVo> res = new Page<ManualModelSearchVo>();
        res.setRecords(new ArrayList<>());
        QueryWrapper queryWrapper = generatorListQueryWrapper(param);
        IPage<ManualModelOm> manualModelOms = baseMapper.selectPage(new Page(1,20),queryWrapper);
        for (ManualModelOm manualModelOm : manualModelOms.getRecords()) {
            ManualModelSearchVo vo = new ManualModelSearchVo();
            BeanUtils.copyProperties(manualModelOm,vo);
            vo.setModelBrand(ManualBrandEnums.getDesc(manualModelOm.getBrandId()));
            res.getRecords().add(vo);
        }
        res.setCurrent(manualModelOms.getCurrent());
        res.setPages(manualModelOms.getPages());
        res.setSize(manualModelOms.getSize());
        res.setTotal(manualModelOms.getTotal());
        return res;
    }

    @Override
    public void doTransManualModelOm() {
        List<ManualModelOm> manualModelOms = baseMapper.selectList(Wrappers.<ManualModelOm>lambdaQuery().eq(ManualModelOm::getBrandId, 2));
        for (ManualModelOm manualModelOm : manualModelOms) {
            String transfer = MachineTranslationUtil.transfer(manualModelOm.getModelName());
            if (StringUtils.isBlank(transfer)){
                continue;
            }
            manualModelOm.setModelName(transfer);
            baseMapper.updateById(manualModelOm);
            log.info(transfer,"process successfull");
        }
    }

    @Override
    public void downloadManualPdfs() {
        List<ManualModelOm> manualModelOms = baseMapper.selectList(Wrappers.<ManualModelOm>lambdaQuery().in(ManualModelOm::getBrandId, Lists.newArrayList(10)));
        Map<String, List<ManualModelOm>> modelMap = manualModelOms.stream().collect(Collectors.groupingBy(ManualModelOm::getModelName));
        String basePath = "/home/manuals";
        for (String modelName : modelMap.keySet()) {
            //创建model文件夹
            if (StringUtils.isBlank(modelName)){
                continue;
            }
            String modelPath = basePath.concat("/").concat(modelName.replaceAll(" ","_").replaceAll("/","&"));
            File modelFile = new File(modelPath);
            if (!modelFile.exists() && !modelFile.mkdir()){
                log.error("model文件夹创建失败->{}",modelName);
                continue;
            }
            //创建year文件夹
            List<ManualModelOm> modelYears = modelMap.get(modelName);
            for (ManualModelOm modelYearBean : modelYears) {
                if (StringUtils.isEmpty(modelYearBean.getModelYear())){
                    continue;
                }
                String yearPath = modelPath.concat("/").concat(modelYearBean.getModelYear());
                File yearFile = new File(yearPath);
                if (!yearFile.exists() && !yearFile.mkdir()){
                    log.error("year文件夹创建失败->{}-{}",modelName,modelYearBean.getModelYear());
                    continue;
                }
                //查询图纸信息
                ManualCatalogOm manualCatalogOm = catalogOmMapper.selectOne(Wrappers.<ManualCatalogOm>lambdaQuery().eq(ManualCatalogOm::getModelId, modelYearBean.getId()));
                if (ObjectUtil.isEmpty(manualCatalogOm) || StringUtils.isBlank(manualCatalogOm.getCatalogUrl())){
                    log.error("未找到{}-{}手册",modelName,modelYearBean.getModelYear());
                    continue;
                }
                if (StringUtils.isNotEmpty(manualCatalogOm.getCatalogPath())){
                    continue;
                }
                byte[] bytes = HttpUtil.getOkHttp(manualCatalogOm.getCatalogUrl());
                if (bytes == null){
                    continue;
                }
                String catalogPath = yearPath.concat("/").concat(String.valueOf(idGenerator.nextId())).concat(".pdf");
                FileOutputStream fileOutputStream = null;
                try {
                    fileOutputStream = new FileOutputStream(catalogPath);
                    fileOutputStream.write(bytes);
                    fileOutputStream.flush();
                    manualCatalogOm.setCatalogPath(catalogPath);
                    catalogOmMapper.updateById(manualCatalogOm);
                    log.info("{}->{}-successfull",modelName,modelYearBean.getModelYear());
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    if (fileOutputStream != null){
                        try {
                            fileOutputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    @Override
    public void uploadManualPdfToMinio() {
        List<ManualCatalogOm> manualCatalogOms = catalogOmMapper.selectList(Wrappers.<ManualCatalogOm>lambdaQuery().isNotNull(ManualCatalogOm::getCatalogPath).ge(ManualCatalogOm::getModelId,4315));
        for (ManualCatalogOm manualCatalogOm : manualCatalogOms) {
            if (StringUtils.isBlank(manualCatalogOm.getCatalogPath())){
                continue;
            }
            byte[] bytes = null;
            try {
                bytes = Files.readAllBytes(Paths.get(manualCatalogOm.getCatalogPath()));
            } catch (IOException e) {
                log.error("未读取到本地文件->{}",manualCatalogOm.getCatalogPath());
            }
            if (bytes == null || bytes.length == 0){
                continue;
            }
            ManualModelOm manualModelOm = baseMapper.selectById(manualCatalogOm.getModelId());
            if (ObjectUtil.isNull(manualModelOm) || StringUtils.isBlank(manualModelOm.getModelName())){
                log.error("未读取到本地文件对应的型号->{}",manualCatalogOm.getModelId());
                continue;
            }
            String modelName = manualModelOm.getModelName();
            modelName = modelName.replaceAll(" ","_");
            modelName = modelName.replaceAll("/","&");
            String fileName = manualCatalogOm.getCatalogPath().substring(manualCatalogOm.getCatalogPath().lastIndexOf("/") + 1);
            String bucketName = "manuals";
            String path = new StringBuilder().append(modelName).append("/").append(manualModelOm.getModelYear()).append("/").append(fileName).toString();
            try {
                MinIoUtil.uploadFile(bytes,bucketName,path);
            } catch (Exception e) {
                log.error("文件上传到minio失败->{}",e);
            }
            manualCatalogOm.setCatalogMinioPath(path);
            catalogOmMapper.updateById(manualCatalogOm);
            log.info("{}=>{}-successfull",manualModelOm.getModelName(),manualModelOm.getModelYear());
        }
    }

    @Override
    public void createThumbnailToMinio() {
        List<ManualCatalogOm> manualCatalogOms = catalogOmMapper.selectList(Wrappers.<ManualCatalogOm>lambdaQuery().isNotNull(ManualCatalogOm::getCatalogPath));
        for (ManualCatalogOm manualCatalogOm : manualCatalogOms) {
            if (StringUtils.isBlank(manualCatalogOm.getCatalogPath())){
                continue;
            }
            String pdfFilePath = manualCatalogOm.getCatalogPath();
            //生成缩略图
            String thumbnailPath = PdfUtil.pdfFirstPageToPng(pdfFilePath, pdfFilePath.substring(0,pdfFilePath.lastIndexOf("/")+1));
            byte[] bytes = null;
            try {
                bytes = Files.readAllBytes(Paths.get(thumbnailPath));
            } catch (IOException e) {
                log.error("未读取到本地文件->{}",thumbnailPath);
            }
            if (bytes == null || bytes.length == 0){
                continue;
            }
            ManualModelOm manualModelOm = baseMapper.selectById(manualCatalogOm.getModelId());
            if (ObjectUtil.isNull(manualModelOm) || StringUtils.isBlank(manualModelOm.getModelName())){
                log.error("未读取到本地文件对应的型号->{}",manualCatalogOm.getModelId());
                continue;
            }
            String modelName = manualModelOm.getModelName();
            modelName = modelName.replaceAll(" ","_");
            modelName = modelName.replaceAll("/","&");
            String fileName = thumbnailPath.substring(pdfFilePath.lastIndexOf("/") + 1);
            String bucketName = "thumbnail";
            String path = new StringBuilder().append(modelName).append("/").append(manualModelOm.getModelYear()).append("/").append(fileName).toString();
            try {
                MinIoUtil.uploadFile(bytes,bucketName,path);
            } catch (Exception e) {
                log.error("文件上传到minio失败->{}",e);
            }
            manualCatalogOm.setCatalogThumbnailPath(path);
            catalogOmMapper.updateById(manualCatalogOm);
            log.info("{}=>{}-successfull",manualModelOm.getModelName(),manualModelOm.getModelYear());
        }
    }

    private QueryWrapper generatorListQueryWrapper(ManualModelSearchDto param){
        QueryWrapper<ManualModelOm> queryWrapper = new QueryWrapper<>();
        if (param.getBrandId() != null){
            queryWrapper.eq("brand_id",param.getBrandId());
        }
        if (StringUtils.isNotEmpty(param.getModelName())){
            queryWrapper.like("model_name","%".concat(param.getModelName()).concat("%"));
        }
        queryWrapper.orderByDesc("model_year");
        return queryWrapper;
    }

    @Override
    public List<ManualModelSearchVo> mpSearchModel(ManualModelSearchDto param,HttpServletRequest request) {
        List<ManualModelSearchVo> res = new LinkedList<>();
        QueryWrapper queryWrapper = generatorListQueryWrapper(param);
        List<ManualModelOm> manualModelOms = baseMapper.selectList(queryWrapper);
        for (ManualModelOm manualModelOm : manualModelOms) {
            ManualModelSearchVo manualModelSearchVo = new ManualModelSearchVo();
            BeanUtils.copyProperties(manualModelOm,manualModelSearchVo);
            manualModelSearchVo.setModelBrand(ManualBrandEnums.getDesc(manualModelOm.getBrandId()));
            res.add(manualModelSearchVo);
        }
        return res;
    }

    @Override
    public ManualModelSearchDetailVo mpSearchModelDetail(String id,HttpServletRequest request) {
        ManualModelOm manualModelOm = baseMapper.selectById(id);
        if (ObjectUtil.isNull(manualModelOm)){
            return null;
        }
        ManualModelSearchDetailVo manualModelSearchDetailVo = new ManualModelSearchDetailVo();
        BeanUtils.copyProperties(manualModelOm,manualModelSearchDetailVo);
        manualModelSearchDetailVo.setModelBrand(ManualBrandEnums.getDesc(manualModelOm.getBrandId()));
        //缩略图查询
        ManualCatalogOm manualCatalogOm = catalogOmMapper.selectOne(Wrappers.<ManualCatalogOm>lambdaQuery().select(ManualCatalogOm::getCatalogThumbnailPath).eq(ManualCatalogOm::getModelId, id));
        if (ObjectUtil.isNotNull(manualCatalogOm) && StringUtils.isNotBlank(manualCatalogOm.getCatalogThumbnailPath())) {
            manualModelSearchDetailVo.setThumbnail(minIoProperties.getDomain().endsWith("/")?minIoProperties.getDomain().concat(manualCatalogOm.getCatalogThumbnailPath()):minIoProperties.getDomain().concat("/").concat(manualCatalogOm.getCatalogThumbnailPath()));
        }
        return manualModelSearchDetailVo;
    }


    @Override
    public Boolean mpGetCatalogToEmail(ManualCatalogToMailDto toMailDto,HttpServletRequest request) {
        String key = RedisConstant.CATALOG_EMAIL_KEY + toMailDto.getToUser();
        if (RedisUtil.hasKey(key) && !toMailDto.getToUser().equals(RedisConstant.IGNORE_EMAIL)){
            throw new MyException(20001,"相同邮箱地址一天只能获取一次");
        }

        ManualCatalogOm manualCatalogOm = catalogOmMapper.selectOne(Wrappers.<ManualCatalogOm>lambdaQuery().eq(ManualCatalogOm::getModelId, toMailDto.getModelId()));
        if (ObjectUtil.isNull(manualCatalogOm) || StringUtils.isBlank(manualCatalogOm.getCatalogPath())){
            throw new MyException(20002,"暂无相关资源");
        }
        //记录数据
        Long toDayEndTime = getToDayEndTime();
        RedisUtil.setEx(key,"1",toDayEndTime, TimeUnit.MILLISECONDS);

        kafkaTemplate.send("mp-queue", JSONObject.toJSONString(toMailDto));
        return true;
    }

    @Override
    public void mpGetCatalogToEmailConsumer(ManualCatalogToMailDto toMailDto) {
        ManualModelOm manualModelOm = baseMapper.selectById(toMailDto.getModelId());
        ManualCatalogOm manualCatalogOm = catalogOmMapper.selectOne(Wrappers.<ManualCatalogOm>lambdaQuery().eq(ManualCatalogOm::getModelId, toMailDto.getModelId()));
        //发送邮件
        File catalogFile = new File(manualCatalogOm.getCatalogPath());
//        File catalogFile = new File("D:\\1092182814020861952.pdf");
        String title = manualModelOm.getModelName()+"-"+manualModelOm.getModelYear();
        EmailUtil.sendFileEmail(toMailDto.getToUser(),title, Strings.EMPTY,catalogFile);
    }

    @Override
    public List<ManualBrand> getAllBrand(HttpServletRequest request) {
        List<ManualBrand> manualBrands = manualBrandMapper.selectList(new QueryWrapper<>());
        return manualBrands;
    }

    private Long getToDayEndTime(){
        long end = DateTime.now().millisOfDay().withMaximumValue().getMillis();
        long now = DateTime.now().getMillis();
        return end - now;
    }
}
